package com.wwj.server.control;

import com.google.gson.Gson;
import com.wwj.core.server.entity.ControlServer;
import com.wwj.core.server.entity.ControlServerConnect;
import com.wwj.core.server.entity.GameServer;
import com.wwj.core.server.entity.NotifyServer;
import com.wwj.core.server.service.IControlServerConnectService;
import com.wwj.core.server.service.IGameServerService;
import com.wwj.core.server.service.INotifyServerService;
import com.wwj.core.wawa.entity.WaWaMachine;
import com.wwj.core.wawa.service.IWaWaMachineService;
import com.wwj.server.control.common.MsgConstants;
import com.wwj.server.control.msg.*;
import com.wwj.server.control.session.SessionImpl;
import com.wwj.server.control.session.SessionManager;
import com.wwj.server.control.utils.SpringContextUtils;
import com.wwj.server.model.Message;
import com.wwj.server.session.Session;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

/**
 * 消息接受处理类
 *
 * @author tysci
 */
public class ServerHandler extends SimpleChannelInboundHandler<Message> {


    private Logger logger = LoggerFactory.getLogger(getClass());

    private IGameServerService gameServerService = (IGameServerService) SpringContextUtils.getContext().getBean("gameServerServiceImpl");

    private INotifyServerService notifyServerService = (INotifyServerService) SpringContextUtils.getContext().getBean("notifyServerServiceImpl");

    private IControlServerConnectService controlServerConnectService = (IControlServerConnectService) SpringContextUtils.getContext().getBean("controlServerConnectServiceImpl");

    private IWaWaMachineService waWaMachineService = (IWaWaMachineService) SpringContextUtils.getContext().getBean("waWaMachineServiceImpl");

    private ControlServer controlServer;

    public ServerHandler(ControlServer controlServer) {
        this.controlServer = controlServer;
    }

    //1.连接注册
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
        //logger.debug("host:{} 开始连接本机...", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
    }

    //2.连接激活
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        //logger.debug("host:{} 连接通道已激活...", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
    }

    /**
     * 接收消息
     */
    //3.数据读取
    @Override
    public void channelRead0(ChannelHandlerContext ctx, Message message) throws Exception {
        //消息分类
        //1.game(client) --> control game注册绑定control (game启动时调用)
        //2.game(client) --> control 上机操作 用户绑定娃娃机
        //3.game(client) --> control 控制娃娃机 投币/上/下/左/右
        //4.娃娃机 --> control 娃娃机注册绑定 session添加
        //5.娃娃机 --> control 抓娃娃结果反馈
        //logger.debug("接收消息 ip={}, data={}", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName(), new String(message.getData()));
        handlerMessage(new SessionImpl(ctx.channel()), message);
    }

    //4.数据读取完毕
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
        //logger.debug("host:{} 消息接收完毕...", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
    }

    /**
     * 断线移除会话
     */
    //5.连接无效
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Session session = new SessionImpl(ctx.channel());
        Object object = session.getAttachment();
        String sessionKey = null;
        //GameServer断线
        if (object instanceof GameServer) {
            GameServer server = (GameServer) object;

            ControlServerConnect connect = controlServerConnectService.findConnect(controlServer.getId(), server.getServerName());
            connect.setConnected(ControlServerConnect.NOT_CONNECTED);
            controlServerConnectService.updateConnect(connect);

            sessionKey = SessionManager.PREFIX_SESSION_KEY_GAME_SERVER + server.getServerName();

        }
        if (object instanceof WaWaMachine) {
            WaWaMachine waWaMachine = (WaWaMachine) object;
            waWaMachine.setIsOnline(WaWaMachine.OFFLINE);
            waWaMachineService.updateMachine(waWaMachine);

            sessionKey = SessionManager.PREFIX_SESSION_KEY_WA_WA_MACHINE + waWaMachine.getCode();
        }

        if (null != sessionKey && !"".equals(sessionKey)) {
            SessionManager.removeSession(sessionKey);
        }

        logger.debug("host:{} sessionKey={} 远程连接已失效...", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName(), sessionKey);
    }

    //6.连接注销
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
        //logger.debug("host:{} 远程连接已注销...", ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        Channel channel = ctx.channel();
        if (!channel.isActive()) {
            logger.info("#######################--客户端-{}断开了长连接！", channel.remoteAddress());
            ctx.close();
        } else {
            ctx.fireExceptionCaught(cause);
            logger.error("#######################", cause);
        }
    }

    /**
     * 消息处理
     *
     * @param session 会话
     * @param message 消息
     */
    private void handlerMessage(Session session, Message message) {
        String sessionKey;
        Object obj;
        switch (message.getType()) {
            //GameServer session 绑定
            case MsgConstants.GAME_SERVER_BIND:
                logger.debug("GET Message「GameServer,ip={}」:{}", session.getRemoteAddress(), new String(message.getData()));
                GameServerBindMsg gameServerBindMsg = new Gson().fromJson(new String(message.getData()), GameServerBindMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_GAME_SERVER + gameServerBindMsg.getServerName();
                try {
                    //GameServer与ControlServer绑定操作
                    //判断是否已注册
                    if (SessionManager.isOnline(sessionKey)) {
                        logger.warn("GameServer重新注册！");
                        SessionManager.removeSession(sessionKey);
                    }
                    //数据入库并更改在线状态然后放入session
                    if (SessionManager.putSession(sessionKey, session)) {
                        GameServer gameServer = gameServerService.findByServerName(gameServerBindMsg.getServerName());
                        if (null == gameServer) {
                            SessionManager.sendMessage(sessionKey, new GameServerBindMsgAck(gameServerBindMsg, "N"));
                            logger.debug("GameServer@{}{}", gameServerBindMsg.getServerName(), "绑定失败");
                            return;
                        } else {
                            ControlServerConnect connect = controlServerConnectService.findConnect(controlServer.getId(), gameServer.getServerName());
                            if (null == connect) {
                                connect = new ControlServerConnect(controlServer.getId(), gameServer.getServerName());
                                controlServerConnectService.createNewConnect(connect);
                            } else {
                                connect.setConnected(ControlServerConnect.CONNECTED);
                                controlServerConnectService.updateConnect(connect);
                            }
                        }
                        session.setAttachment(gameServer);
                        logger.debug("GameServer@{}{}", gameServerBindMsg.getServerName(), "绑定成功");
                        SessionManager.sendMessage(sessionKey, new GameServerBindMsgAck(gameServerBindMsg, "Y"));
                        return;
                    }
                    logger.debug("GameServer@{}{}", gameServerBindMsg.getServerName(), "绑定失败");
                    SessionManager.sendMessage(sessionKey, new GameServerBindMsgAck(gameServerBindMsg, "N"));
                } catch (Exception e) {
                    logger.error("绑定GameServer异常：", e);
                    SessionManager.sendMessage(sessionKey, new GameServerBindMsgAck(gameServerBindMsg, "N"));
                }
                break;
            //GameServer游戏控制
            case MsgConstants.GAME_SERVER_CMD:
                logger.debug("GET Message「GameServer,ip={}」:{}", session.getRemoteAddress(), new String(message.getData()));
                GameServerCmdMsg gameServerCmdMsg = new Gson().fromJson(new String(message.getData()), GameServerCmdMsg.class);
                obj = session.getAttachment();
                sessionKey = SessionManager.PREFIX_SESSION_KEY_WA_WA_MACHINE + gameServerCmdMsg.getDeviceId();
                logger.debug("GameServer进行游戏操控，命令号={}， deviceId={}, sessionKey={}", gameServerCmdMsg.getCmd(), gameServerCmdMsg.getDeviceId(), sessionKey);
                if (null != obj && obj instanceof GameServer) {
                    GameServer gameServer = (GameServer) obj;
                    if (SessionManager.isOnline(sessionKey)) {
                        //发送协议至娃娃机
                        SessionManager.sendMessage(sessionKey, new DeviceCmdMsg(gameServerCmdMsg, gameServer.getServerName()));
                    } else {
                        logger.error("娃娃机 sessionKey={} 不在线", sessionKey);
                        sessionKey = SessionManager.PREFIX_SESSION_KEY_GAME_SERVER + gameServer.getServerName();
                        SessionManager.sendMessage(sessionKey, new GameServerCmdMsgAck(gameServerCmdMsg, "N"));
                    }
                }
                break;
            //GameServer心跳
            case MsgConstants.GAME_SERVER_HEARTBEAT:
                GameServerHeartbeatMsg gameServerHeartbeatMsg = new Gson().fromJson(new String(message.getData()), GameServerHeartbeatMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_GAME_SERVER + gameServerHeartbeatMsg.getServerName();
                SessionManager.sendMessage(sessionKey, new GameServerHeartbeatMsgAck(gameServerHeartbeatMsg));
                break;
            //娃娃机 session 绑定逻辑
            case MsgConstants.DEVICE_LOGIN:
                logger.debug("GET Message「Device,ip={}」:{}", session.getRemoteAddress(), new String(message.getData()));
                DeviceLoginMsg deviceLoginMsg = new Gson().fromJson(new String(message.getData()), DeviceLoginMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_WA_WA_MACHINE + deviceLoginMsg.getDeviceId();
                try {
                    //娃娃机与ControlServer绑定操作
                    //判断是否已注册
                    if (SessionManager.isOnline(sessionKey)) {
                        SessionManager.removeSession(sessionKey);
                    }
                    //数据入库并更改在线状态然后放入session
                    if (SessionManager.putSession(sessionKey, session)) {
                        WaWaMachine waWaMachine = waWaMachineService.findByDeviceId(deviceLoginMsg.getDeviceId());
                        if (null == waWaMachine) {
                            waWaMachine = new WaWaMachine(session.getRemoteAddress(), deviceLoginMsg.getDeviceId(), deviceLoginMsg.getRoomId(),
                                    deviceLoginMsg.getChannelName(), deviceLoginMsg.getCId1(), deviceLoginMsg.getCId2());
                            waWaMachine.setStatus(WaWaMachine.STATUS_INIT);
                            waWaMachineService.createNewMachine(waWaMachine);
                        } else {
                            waWaMachine.setIsOnline(GameServer.ONLINE);
                            waWaMachine.setIp(session.getRemoteAddress());
                            waWaMachine.setRoomId(deviceLoginMsg.getRoomId());
                            waWaMachine.setChannelName(deviceLoginMsg.getChannelName());
                            if(null != deviceLoginMsg.getCId1() && !"".equals(deviceLoginMsg.getCId1()))
                                waWaMachine.setCId1(deviceLoginMsg.getCId1());
                            if(null != deviceLoginMsg.getCId2() && !"".equals(deviceLoginMsg.getCId2()))
                                waWaMachine.setCId2(deviceLoginMsg.getCId2());
                            waWaMachineService.updateMachine(waWaMachine);
                        }
                        session.setAttachment(waWaMachine);
                        logger.debug("WaWaMachine@{}{}", deviceLoginMsg.getDeviceId(), "绑定成功");
                        SessionManager.sendMessage(sessionKey, new DeviceLoginMsgAck(deviceLoginMsg, "Y"));
                        return;
                    }
                    logger.debug("WaWaMachine@{}{}", deviceLoginMsg.getDeviceId(), "绑定失败");
                    SessionManager.sendMessage(sessionKey, new DeviceLoginMsgAck(deviceLoginMsg, "N"));
                } catch (Exception e) {
                    logger.error("绑定GameServer异常：", e);
                    SessionManager.sendMessage(sessionKey, new DeviceLoginMsgAck(deviceLoginMsg, "N"));
                }
                break;
            //设备操控反馈
            case MsgConstants.DEVICE_CMD_ACK:
                logger.debug("GET Message「Device,ip={}」:{}", session.getRemoteAddress(), new String(message.getData()));
                DeviceCmdMsgAck deviceCmdMsgAck = new Gson().fromJson(new String(message.getData()), DeviceCmdMsgAck.class);
                obj = session.getAttachment();
                sessionKey = SessionManager.PREFIX_SESSION_KEY_GAME_SERVER + deviceCmdMsgAck.getServerName();
                if (null != obj && obj instanceof WaWaMachine) {
                    //WaWaMachine wwm = (WaWaMachine) obj;
                    SessionManager.sendMessage(sessionKey, new GameServerCmdMsgAck(deviceCmdMsgAck));
                }
                break;
            //抓取结果反馈
            case MsgConstants.DEVICE_GAME_RESULT:
                logger.debug("GET Message「Device,ip={}」:{}", session.getRemoteAddress(), new String(message.getData()));
                DeviceGameResultMsg deviceGameResultMsg = new Gson().fromJson(new String(message.getData()), DeviceGameResultMsg.class);
                obj = session.getAttachment();
                sessionKey = SessionManager.PREFIX_SESSION_KEY_GAME_SERVER + deviceGameResultMsg.getServerName();
                if (null != obj && obj instanceof WaWaMachine) {
                    SessionManager.sendMessage(sessionKey, new GameServerGameResultMsg(deviceGameResultMsg));
                    if (deviceGameResultMsg.getResult().toUpperCase().equals("Y")) {
                        SessionManager.sendMessageToAll(SessionManager.PREFIX_SESSION_KEY_NOTIFY_SERVER, new NotifyUserCatchMsg(deviceGameResultMsg.getUserId()));
                    }
                }
                break;
            //设备状态查询反馈
            case MsgConstants.DEVICE_QUERY_ACK:
                logger.debug("GET Message「Device,ip={}」:{}", session.getRemoteAddress(), new String(message.getData()));
                break;
            case MsgConstants.DEVICE_STATE_CHANGE:
                //设备状态修改通知
                logger.debug("GET Message「Device,ip={}」:{}", session.getRemoteAddress(), new String(message.getData()));
//                try {
//                    DeviceStateChangeMsg deviceStateChangeMsg = new Gson().fromJson(new String(message.getData()), DeviceStateChangeMsg.class);
//                    String deviceId = deviceStateChangeMsg.getDeviceId();
//                    WaWaMachine waWaMachine = waWaMachineService.findByDeviceId(deviceId);
//                    Integer state = new Integer(deviceStateChangeMsg.getState());
//                    switch (state){
//                        case 0:
//                            waWaMachine.setStatus(1);
//                            break;
//                        case 1:
//                            waWaMachine.setStatus(2);
//                            break;
//                        case 2:
//                            waWaMachine.setStatus(3);
//                            break;
//                        default:
//                            logger.debug("未知状态码:"+new String(message.getData()));
//                            break;
//                    }
//                    waWaMachineService.updateMachine(waWaMachine);
//                } catch (Exception e) {
//                    logger.error("更新设备信息出错。。。");
//                    e.printStackTrace();
//                }
                break;
            //设备心跳
            case MsgConstants.DEVICE_HEARTBEAT:
                DeviceHeartbeatMsg deviceHeartbeatMsg = new Gson().fromJson(new String(message.getData()), DeviceHeartbeatMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_WA_WA_MACHINE + deviceHeartbeatMsg.getDeviceId();
                SessionManager.sendMessage(sessionKey, new DeviceHeartbeatMsgAck(deviceHeartbeatMsg));
                break;
            //NotifyServer session 绑定
            case MsgConstants.NOTIFY_SERVER_BIND:
                logger.debug("GET Message「NotifyServer,ip={}」:{}", session.getRemoteAddress(), new String(message.getData()));
                NotifyServerBindMsg notifyServerBindMsg = new Gson().fromJson(new String(message.getData()), NotifyServerBindMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_NOTIFY_SERVER + notifyServerBindMsg.getServerName();
                try {
                    //NotifyServer与ControlServer绑定操作
                    //判断是否已注册
                    if (SessionManager.isOnline(sessionKey)) {
                        SessionManager.removeSession(sessionKey);
                    }
                    //数据入库并更改在线状态然后放入session
                    if (SessionManager.putSession(sessionKey, session)) {
                        NotifyServer notifyServer = notifyServerService.findByServerName(notifyServerBindMsg.getServerName());
                        if (null == notifyServer) {
                            SessionManager.sendMessage(sessionKey, new NotifyServerBindMsgAck(notifyServerBindMsg, "N"));
                            logger.debug("GameServer@{}{}", notifyServerBindMsg.getServerName(), "绑定失败");
                            return;
                        } else {
                            ControlServerConnect connect = controlServerConnectService.findConnect(controlServer.getId(), notifyServer.getServerName());
                            if (null == connect) {
                                connect = new ControlServerConnect(controlServer.getId(), notifyServer.getServerName());
                                controlServerConnectService.createNewConnect(connect);
                            } else {
                                connect.setConnected(ControlServerConnect.CONNECTED);
                                controlServerConnectService.updateConnect(connect);
                            }
                        }
                        session.setAttachment(notifyServer);
                        logger.debug("NotifyServer@{}{}", notifyServerBindMsg.getServerName(), "绑定成功");
                        SessionManager.sendMessage(sessionKey, new NotifyServerBindMsgAck(notifyServerBindMsg, "Y"));
                        return;
                    }
                    logger.debug("NotifyServer@{}{}", notifyServerBindMsg.getServerName(), "绑定失败");
                    SessionManager.sendMessage(sessionKey, new NotifyServerBindMsgAck(notifyServerBindMsg, "N"));
                } catch (Exception e) {
                    logger.error("绑定NotifyServer异常：", e);
                    SessionManager.sendMessage(sessionKey, new NotifyServerBindMsgAck(notifyServerBindMsg, "N"));
                }
                break;
            //NotifyServer心跳
            case MsgConstants.NOTIFY_SERVER_HEARTBEAT:
                NotifyServerHeartbeatMsg notifyServerHeartbeatMsg = new Gson().fromJson(new String(message.getData()), NotifyServerHeartbeatMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_NOTIFY_SERVER + notifyServerHeartbeatMsg.getServerName();
                SessionManager.sendMessage(sessionKey, new NotifyServerHeartbeatMsgAck(notifyServerHeartbeatMsg));
                break;
            default:
                logger.debug("不存在的设备协议 ip={}, data={}", session.getRemoteAddress(), new String(message.getData()));

        }
    }
}